package com.autoagent.ai_live_master.webSocket.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;

import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DisconnectListener;
import com.corundumstudio.socketio.listener.DataListener;
import com.autoagent.ai_live_master.common.event.WebSocketConnectionEvent;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
public class SocketIOHandler {

    private final SocketIOServer socketIOServer;
    
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    // 使用ConcurrentHashMap来存储客户端，提供更好的线程安全性

    // 按照 roomId 分组存储客户端连接
    private final Map<String, Set<SocketIOClient>> roomClients = new ConcurrentHashMap<>();

    public SocketIOHandler(SocketIOServer socketIOServer) {
        this.socketIOServer = socketIOServer;
    }

    @PostConstruct
    public void init() {
        socketIOServer.addConnectListener(onConnect());
        socketIOServer.addDisconnectListener(onDisconnect());
        socketIOServer.addEventListener("live-master-message", String.class, onMessageReceived());

        socketIOServer.start();
        log.info("SocketIOServer started on {}:{}", 
                socketIOServer.getConfiguration().getHostname(), 
                socketIOServer.getConfiguration().getPort());
    }

    @PreDestroy
    public void shutdown() {
        try {
            socketIOServer.stop();
            log.info("SocketIOServer stopped gracefully");
        } catch (Exception e) {
            log.error("Error stopping SocketIOServer", e);
        }
    }

    private ConnectListener onConnect() {
        return client -> {
            try {
                String roomId = client.getHandshakeData().getSingleUrlParam("roomId");
                if (roomId == null || roomId.isEmpty()) {
/*                    log.warn("Client connection rejected: missing roomId");
                    client.disconnect();
                    return;*/
                    roomId="000000";
                    log.warn("No roomId provided. Using default roomId: {}", roomId);
                }

                // 加入房间对应的 client 集合
                roomClients
                        .computeIfAbsent(roomId, k -> ConcurrentHashMap.newKeySet())
                        .add(client);

                log.info("Client connected: sessionId={}, roomId={}, ip={}, total in room: {}",
                        client.getSessionId(),
                        roomId,
                        client.getHandshakeData().getAddress(),
                        roomClients.get(roomId).size());

                // 给新连接的客户端发送欢迎消息
                client.sendEvent("live-master-message",
                        "{\"type\":\"welcome\",\"message\":\"Connected to room: " + roomId + "\"}");

                // 发布WebSocket连接事件，让其他服务处理定式话术发送
                eventPublisher.publishEvent(new WebSocketConnectionEvent(this, roomId, "socketio"));
                log.info("SocketIO连接建立，已发布连接事件，房间ID: {}", roomId);

            } catch (Exception e) {
                log.error("Error handling client connection: {}", e.getMessage(), e);
            }
        };
    }

    private DisconnectListener onDisconnect() {
        return client -> {
            try {
                String roomId = client.getHandshakeData().getSingleUrlParam("roomId");
                if (roomId != null && roomClients.containsKey(roomId)) {
                    roomClients.get(roomId).remove(client);
                    log.info("Client disconnected: sessionId={}, roomId={}, remaining in room: {}",
                            client.getSessionId(), roomId, roomClients.get(roomId).size());

                    // 清理空房间
                    if (roomClients.get(roomId).isEmpty()) {
                        roomClients.remove(roomId);
                        log.info("Room {} is now empty and removed", roomId);
                    }
                }
            } catch (Exception e) {
                log.error("Error handling client disconnection: {}", e.getMessage(), e);
            }
        };
    }

    private DataListener<String> onMessageReceived() {
        return (client, data, ackSender) -> {
            try {
                log.info("Message received from client (sessionId={}): {}", 
                        client.getSessionId(), data);

                // 发送确认给客户端
                if (ackSender.isAckRequested()) {
                    ackSender.sendAckData("Message received");
                }
            } catch (Exception e) {
                log.error("Error handling received message: {}", e.getMessage(), e);
            }
        };
    }

    public void broadcast(String roomId,String message) {
//        Set<SocketIOClient> clients = roomClients.get(roomId);
        Set<SocketIOClient> clients = roomClients.get("000000");
        if (clients == null || clients.isEmpty()) {
            log.debug("No clients in room {} to broadcast to", roomId);
            return;
        }

        int successCount = 0;
        int failCount = 0;

        Iterator<SocketIOClient> iterator = clients.iterator();
        while (iterator.hasNext()) {
            SocketIOClient client = iterator.next();
            try {
                if (client.isChannelOpen()) {
                    client.sendEvent("live-master-message", message);
                    successCount++;
                } else {
                    iterator.remove();
                }
            } catch (Exception e) {
                iterator.remove();
                failCount++;
                log.error("Failed to send message to client {}: {}", client.getSessionId(), e.getMessage());
            }
        }

        log.info("Broadcasted to room {} (success: {}, failed: {}): {}", roomId, successCount, failCount, message);

        // 房间为空，清理
        if (clients.isEmpty()) {
            roomClients.remove(roomId);
            log.info("Room {} cleaned up after broadcast", roomId);
        }
    }

    public boolean hasConnectedClients(String roomId) {
//        Set<SocketIOClient> clients = roomClients.get(roomId);
        Set<SocketIOClient> clients = roomClients.get("000000");
        return clients != null && !clients.isEmpty();
    }

    public int getConnectedClientCount(String roomId) {
        Set<SocketIOClient> clients = roomClients.get(roomId);
        return clients != null ? clients.size() : 0;
    }
}